/*
 *                 [[ Frozen-Bubble ]]
 *
 * Copyright (c) 2000-2003 Guillaume Cottenceau.
 * Java sourcecode - Copyright (c) 2003 Glenn Sanson.
 *
 * This code is distributed under the GNU General Public License
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * Artwork:
 *    Alexis Younes <73lab at free.fr>
 *      (everything but the bubbles)
 *    Amaury Amblard-Ladurantie <amaury at linuxfr.org>
 *      (the bubbles)
 *
 * Soundtrack:
 *    Matthias Le Bidan <matthias.le_bidan at caramail.com>
 *      (the three musics and all the sound effects)
 *
 * Design & Programming:
 *    Guillaume Cottenceau <guillaume.cottenceau at free.fr>
 *      (design and manage the project, whole Perl sourcecode)
 *
 * Java version:
 *    Glenn Sanson <glenn.sanson at free.fr>
 *      (whole Java sourcecode, including JIGA classes
 *             http://glenn.sanson.free.fr/jiga/)
 *
 * Android port:
 *    Pawel Aleksander Fedorynski <pfedor@fuw.edu.pl>
 *    Copyright (c) Google Inc.
 *
 *          [[ http://glenn.sanson.free.fr/fb/ ]]
 *          [[ http://www.frozen-bubble.org/   ]]
 */

package com.example.lianliankdemo;

import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;

import java.util.Vector;

/**
 * 泡泡精灵类
 */
public class BubbleSprite extends Sprite {
    private static double FALL_SPEED = 1.;
    private static double MAX_BUBBLE_SPEED = 8.;
    private static double MINIMUM_DISTANCE = 841.;

    private int color;

    private BmpWrap bubbleFace;
    /**
     * 色盲模式的精灵包装器
     */
    private BmpWrap bubbleBlindFace;
    /**
     * 失败的时候冰冻住的精灵的包装器
     */
    private BmpWrap frozenFace;
    /**
     * 闪烁背景(整体闪烁的时候的背景)
     */
    private BmpWrap bubbleBlink;
    private BmpWrap[] bubbleFixed;
    private FrozenGame frozen;
    private BubbleManager bubbleManager;
    private double moveX, moveY;
    private boolean fixed;

    private double realX, realY;
    private boolean blink;
    private boolean released;

    private boolean checkJump;
    private boolean checkFall;

    private int fixedAnim;

    private SoundManager soundManager;

    public void saveState(Bundle map, Vector savedSprites) {
        if (getSavedId() != -1) {
            return;
        }
        super.saveState(map, savedSprites);
        map.putInt(String.format("%d-color", getSavedId()), color);
        map.putDouble(String.format("%d-moveX", getSavedId()), moveX);
        map.putDouble(String.format("%d-moveY", getSavedId()), moveY);
        map.putDouble(String.format("%d-realX", getSavedId()), realX);
        map.putDouble(String.format("%d-realY", getSavedId()), realY);
        map.putBoolean(String.format("%d-fixed", getSavedId()), fixed);
        map.putBoolean(String.format("%d-blink", getSavedId()), blink);
        map.putBoolean(String.format("%d-released", getSavedId()), released);
        map.putBoolean(String.format("%d-checkJump", getSavedId()), checkJump);
        map.putBoolean(String.format("%d-checkFall", getSavedId()), checkFall);
        map.putInt(String.format("%d-fixedAnim", getSavedId()), fixedAnim);
        map.putBoolean(String.format("%d-frozen", getSavedId()),
                bubbleFace == frozenFace ? true : false);
    }

    public int getTypeId() {
        return Sprite.TYPE_BUBBLE;
    }

    public BubbleSprite(Rect area, int color, double moveX, double moveY,
                        double realX, double realY, boolean fixed, boolean blink,
                        boolean released, boolean checkJump, boolean checkFall,
                        int fixedAnim, BmpWrap bubbleFace,
                        BmpWrap bubbleBlindFace, BmpWrap frozenFace,
                        BmpWrap[] bubbleFixed, BmpWrap bubbleBlink,
                        BubbleManager bubbleManager, SoundManager soundManager,
                        FrozenGame frozen) {
        super(area);
        this.color = color;
        this.moveX = moveX;
        this.moveY = moveY;
        this.realX = realX;
        this.realY = realY;
        this.fixed = fixed;
        this.blink = blink;
        this.released = released;
        this.checkJump = checkJump;
        this.checkFall = checkFall;
        this.fixedAnim = fixedAnim;
        this.bubbleFace = bubbleFace;
        this.bubbleBlindFace = bubbleBlindFace;
        this.frozenFace = frozenFace;
        this.bubbleFixed = bubbleFixed;
        this.bubbleBlink = bubbleBlink;
        this.bubbleManager = bubbleManager;
        this.soundManager = soundManager;
        this.frozen = frozen;
    }

    /**
     * @param area
     * @param direction       好像是运动轨迹方向的加速度（角度越倾斜，速度增加越快）
     * @param color
     * @param bubbleFace
     * @param bubbleBlindFace
     * @param frozenFace
     * @param bubbleFixed
     * @param bubbleBlink
     * @param bubbleManager
     * @param soundManager
     * @param frozen
     */
    public BubbleSprite(Rect area, double direction, int color, BmpWrap bubbleFace,
                        BmpWrap bubbleBlindFace, BmpWrap frozenFace,
                        BmpWrap[] bubbleFixed, BmpWrap bubbleBlink,
                        BubbleManager bubbleManager, SoundManager soundManager,
                        FrozenGame frozen) {
        super(area);

        this.color = color;
        this.bubbleFace = bubbleFace;
        this.bubbleBlindFace = bubbleBlindFace;
        this.frozenFace = frozenFace;
        this.bubbleFixed = bubbleFixed;
        this.bubbleBlink = bubbleBlink;
        this.bubbleManager = bubbleManager;
        this.soundManager = soundManager;
        this.frozen = frozen;

        //Math.cos/Math.sin参数单位弧度角
        this.moveX = MAX_BUBBLE_SPEED * -Math.cos(direction * Math.PI / 180.);
        this.moveY = MAX_BUBBLE_SPEED * -Math.sin(direction * Math.PI / 180.);
//        this.moveX = MAX_BUBBLE_SPEED * -Math.cos(direction * Math.PI / 40.);
//        this.moveY = MAX_BUBBLE_SPEED * -Math.sin(direction * Math.PI / 40.);
        //TODO here ..............................................................
        //弧度--->度：currentDirection-->(currentDirection * 180 / Math.PI)
//        this.moveX = MAX_BUBBLE_SPEED * -Math.cos(direction * 180 / Math.PI);
//        this.moveY = MAX_BUBBLE_SPEED * -Math.sin(direction * 180 / Math.PI);

        this.realX = area.left;
        this.realY = area.top;

        fixed = false;
        fixedAnim = -1;
    }

    public BubbleSprite(Rect area, int color, BmpWrap bubbleFace,
                        BmpWrap bubbleBlindFace, BmpWrap frozenFace,
                        BmpWrap bubbleBlink, BubbleManager bubbleManager,
                        SoundManager soundManager, FrozenGame frozen) {
        super(area);

        this.color = color;
        this.bubbleFace = bubbleFace;
        this.bubbleBlindFace = bubbleBlindFace;
        this.frozenFace = frozenFace;
        this.bubbleBlink = bubbleBlink;
        this.bubbleManager = bubbleManager;
        this.soundManager = soundManager;
        this.frozen = frozen;

        this.realX = area.left;
        this.realY = area.top;

        fixed = true;
        fixedAnim = -1;
        bubbleManager.addBubble(bubbleFace);
    }

    Point currentPosition() {
        //找数组下标
        int posY = (int) Math.floor((realY - 28. - frozen.getMoveDown()) / 28.);
        int posX = (int) Math.floor((realX - 174.) / 32. + 0.5 * (posY % 2));

        if (posX > 7) {
            posX = 7;
        }

        if (posX < 0) {
            posX = 0;
        }

        if (posY < 0) {
            posY = 0;
        }

        return new Point(posX, posY);
    }

    public void removeFromManager() {
        bubbleManager.removeBubble(bubbleFace);
    }

    public boolean fixed() {
        return fixed;
    }

    public boolean checked() {
        return checkFall;
    }

    public boolean released() {
        return released;
    }

    public void moveDown() {
        if (fixed) {
            realY += 28.;
        }

        super.absoluteMove(new Point((int) realX, (int) realY));
    }

    /**
     * 发送中精灵做移动
     * 1、找到当前移动的位置(数组下标)
     * 2、找到移动过程中相邻位置的泡泡
     * 3、进行碰撞检测
     */
    public void move() {
        realX += moveX;

        if (realX >= 414.) {//碰到右边界
            moveX = -moveX;
            realX += (414. - realX);
            //碰壁回弹的声音
            soundManager.playSound(FrozenBubble.SOUND_REBOUND);
        } else if (realX <= 190.) {//碰到左边界
            moveX = -moveX;
            realX += (190. - realX);
            soundManager.playSound(FrozenBubble.SOUND_REBOUND);
        }

        realY += moveY;

        //找到当前移动的位置(数组下标)
        Point currentPosition = currentPosition();
        //找到移动过程中相邻位置的泡泡
        Vector neighbors = getNeighbors(currentPosition);

        //进行碰撞检测
        if (checkCollision(neighbors) || realY < 44. + frozen.getMoveDown()) {
            realX = 190. + currentPosition.x * 32 - (currentPosition.y % 2) * 16;
            realY = 44. + currentPosition.y * 28 + frozen.getMoveDown();

            fixed = true;

            Vector checkJump = new Vector();
            this.checkJump(checkJump, neighbors);

            BubbleSprite[][] grid = frozen.getGrid();

            //有泡泡可消除
            if (checkJump.size() >= 3) {
                released = true;

                for (int i = 0; i < checkJump.size(); i++) {
                    BubbleSprite current = (BubbleSprite) checkJump.elementAt(i);
                    Point currentPoint = current.currentPosition();

                    //添加上跳的泡泡
                    frozen.addJumpingBubble(current);
                    if (i > 0) {
                        current.removeFromManager();
                    }
                    grid[currentPoint.x][currentPoint.y] = null;
                }

                for (int i = 0; i < 8; i++) {
                    if (grid[i][0] != null) {
                        grid[i][0].checkFall();
                    }
                }

                for (int i = 0; i < 8; i++) {
                    for (int j = 0; j < 12; j++) {
                        if (grid[i][j] != null) {
                            if (!grid[i][j].checked()) {
                                //添加下落的小球
                                frozen.addFallingBubble(grid[i][j]);
                                grid[i][j].removeFromManager();
                                grid[i][j] = null;
                            }
                        }
                    }
                }
                //泡泡消除的声音
                soundManager.playSound(FrozenBubble.SOUND_DESTROY);
            }
            //无泡泡可消除，则要添加新泡泡
            else {
                bubbleManager.addBubble(bubbleFace);
                grid[currentPosition.x][currentPosition.y] = this;
                moveX = 0.;
                moveY = 0.;
                fixedAnim = 0;
                //泡泡黏住的声音
                soundManager.playSound(FrozenBubble.SOUND_STICK);
            }
        }

        super.absoluteMove(new Point((int) realX, (int) realY));
    }

    /**
     * 找到相邻位置的泡泡
     *
     * @param p
     * @return
     */
    Vector getNeighbors(Point p) {
        BubbleSprite[][] grid = frozen.getGrid();

        Vector list = new Vector();

        if ((p.y % 2) == 0) {
            if (p.x > 0) {
                list.addElement(grid[p.x - 1][p.y]);
            }

            if (p.x < 7) {
                list.addElement(grid[p.x + 1][p.y]);

                if (p.y > 0) {
                    list.addElement(grid[p.x][p.y - 1]);
                    list.addElement(grid[p.x + 1][p.y - 1]);
                }

                if (p.y < 12) {
                    list.addElement(grid[p.x][p.y + 1]);
                    list.addElement(grid[p.x + 1][p.y + 1]);
                }
            } else {
                if (p.y > 0) {
                    list.addElement(grid[p.x][p.y - 1]);
                }

                if (p.y < 12) {
                    list.addElement(grid[p.x][p.y + 1]);
                }
            }
        } else {
            if (p.x < 7) {
                list.addElement(grid[p.x + 1][p.y]);
            }

            if (p.x > 0) {
                list.addElement(grid[p.x - 1][p.y]);

                if (p.y > 0) {
                    list.addElement(grid[p.x][p.y - 1]);
                    list.addElement(grid[p.x - 1][p.y - 1]);
                }

                if (p.y < 12) {
                    list.addElement(grid[p.x][p.y + 1]);
                    list.addElement(grid[p.x - 1][p.y + 1]);
                }
            } else {
                if (p.y > 0) {
                    list.addElement(grid[p.x][p.y - 1]);
                }

                if (p.y < 12) {
                    list.addElement(grid[p.x][p.y + 1]);
                }
            }
        }

        return list;
    }

    /**
     * 检查跳动（递归）
     */
    void checkJump(Vector jump, BmpWrap compare) {
        if (checkJump) {
            return;
        }
        checkJump = true;

        if (this.bubbleFace == compare) {
            checkJump(jump, this.getNeighbors(this.currentPosition()));
        }
    }

    /**
     * 检查跳动（递归）
     */
    void checkJump(Vector jump, Vector neighbors) {
        jump.addElement(this);

        for (int i = 0; i < neighbors.size(); i++) {
            BubbleSprite current = (BubbleSprite) neighbors.elementAt(i);

            if (current != null) {
                current.checkJump(jump, this.bubbleFace);
            }
        }
    }

    /**
     * 检查下落（递归）
     */
    public void checkFall() {
        if (checkFall) {
            return;
        }
        checkFall = true;

        Vector v = this.getNeighbors(this.currentPosition());

        for (int i = 0; i < v.size(); i++) {
            BubbleSprite current = (BubbleSprite) v.elementAt(i);

            if (current != null) {
                current.checkFall();
            }
        }
    }

    /**
     * 碰撞检测
     *
     * @param neighbors
     * @return
     */
    boolean checkCollision(Vector neighbors) {
        for (int i = 0; i < neighbors.size(); i++) {
            BubbleSprite current = (BubbleSprite) neighbors.elementAt(i);
            if (current != null) {
                if (checkCollision(current)) {
                    return true;
                }
            }
        }

        return false;
    }
    //---------------------------------------------------------------------------------------

    /**
     * 碰撞检测，检检测sprite和当前对象是否有碰撞
     *
     * @param sprite
     * @return
     */
    boolean checkCollision(BubbleSprite sprite) {
//        double value =
//                (sprite.getSpriteArea().left - this.realX) *
//                        (sprite.getSpriteArea().left - this.realX) +
//                        (sprite.getSpriteArea().top - this.realY) *
//                                (sprite.getSpriteArea().top - this.realY);
//        return (value < MINIMUM_DISTANCE);
        int r1 = 16;
        int r2 = 16;
        int x1 = sprite.getSpriteArea().left + 16;
        int y1 = sprite.getSpriteArea().top + 16;
        int x2 = (int) realX + 16;
        int y2 = (int) realY + 16;
        return isCollisionWithCircle(x1, y1, x2, y2, r1, r2);
    }

    /**
     * 矩形碰撞
     * 检测两个矩形是否碰撞
     *
     * @return
     */
    private boolean isCollsionWithRect(int x1, int y1, int w1, int h1,
                                       int x2, int y2, int w2, int h2) {
        if (x1 >= x2 && x1 >= x2 + w2) {
            return false;
        } else if (x1 <= x2 && x1 + w1 <= x2) {
            return false;
        } else if (y1 >= y2 && y1 >= y2 + h2) {
            return false;
        } else if (y1 <= y2 && y1 + h1 <= y2) {
            return false;
        }
        return true;
    }

    /**
     * 点和矩形碰撞
     *
     * @param x1 点
     * @param y1 点
     * @param x2 矩形view x
     * @param y2 矩形view y
     * @param w  矩形view 宽
     * @param h  矩形view 高
     * @return
     */
    private boolean isCollsion(int x1, int y1, int x2, int y2, int w, int h) {
//        if (x1 >= x2 && x1 <= x2 + w && y1 >= y2 && y1 <= y2 + h) {
//            return true;
//        }
//        return false;
        return (x1 >= x2 && x1 <= x2 + w && y1 >= y2 && y1 <= y2 + h);
    }

    /**
     * 圆形碰撞
     *
     * @param x1 圆形1的圆心X坐标
     * @param y1 圆形1的圆心Y坐标
     * @param x2 圆形2的圆心X坐标
     * @param y2 圆形2的圆心Y坐标
     * @param r1 圆形1的半径
     * @param r2 圆形2的半径
     * @return
     */
    private boolean isCollisionWithCircle(int x1, int y1, int x2, int y2,
                                          int r1, int r2) {
        // Math.sqrt:开平方
        // Math.pow(double x, double y): X的Y次方
        //直角坐标系，依点1和点2做平行线，|x1-x2|为横向直角边，|y1-y2|为纵向直角边 依勾股定理 c^2=a^2+b^2
//        if (Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) <= r1 + r2) {
//            // 如果两圆的圆心距小于或等于两圆半径和则认为发生碰撞
//            return true;
//        }
//        return false;
        return (Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) <= r1 + r2);
    }

    //---------------------------------------------------------------------------------------

    /**
     * 跳动
     */
    public void jump() {
        if (fixed) {
            moveX = -6. + frozen.getRandom().nextDouble() * 12.;
            moveY = -5. - frozen.getRandom().nextDouble() * 10.;

            fixed = false;
        }

        moveY += FALL_SPEED;
        realY += moveY;
        realX += moveX;

        super.absoluteMove(new Point((int) realX, (int) realY));

        if (realY >= 680.) {
            frozen.deleteJumpingBubble(this);
        }
    }

    /**
     * 下落
     */
    public void fall() {
        if (fixed) {
            moveY = frozen.getRandom().nextDouble() * 5.;
        }

        fixed = false;

        moveY += FALL_SPEED;
        realY += moveY;

        super.absoluteMove(new Point((int) realX, (int) realY));

        if (realY >= 680.) {
            frozen.deleteFallingBubble(this);
        }
    }

    public void blink() {
        blink = true;
    }

    public void frozenify() {
        changeSpriteArea(new Rect(getSpritePosition().x - 1, getSpritePosition().y - 1,
                34, 42));
        bubbleFace = frozenFace;
    }

    public final void paint(Canvas c, double scale, int dx, int dy) {
        checkJump = false;
        checkFall = false;

        Point p = getSpritePosition();

        if (blink && bubbleFace != frozenFace) {
            blink = false;
            drawImage(bubbleBlink, p.x, p.y, c, scale, dx, dy);
        } else {
            if (FrozenBubble.getMode() == FrozenBubble.GAME_NORMAL ||
                    bubbleFace == frozenFace) {
                drawImage(bubbleFace, p.x, p.y, c, scale, dx, dy);
            } else {
                drawImage(bubbleBlindFace, p.x, p.y, c, scale, dx, dy);
            }
        }

        if (fixedAnim != -1) {
            drawImage(bubbleFixed[fixedAnim], p.x, p.y, c, scale, dx, dy);
            fixedAnim++;
            if (fixedAnim == 6) {
                fixedAnim = -1;
            }
        }
    }
}
